package com.cls.common.aspect;

import com.cls.common.annotation.ControllerEndpoint;
import com.cls.common.exception.MyException;
import com.cls.common.exception.RepeatSubmitException;
import com.cls.common.utils.MyUtil;
import com.cls.common.utils.StringUtils;
import com.cls.monitor.service.ILogService;
import com.cls.system.entity.User;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * @author WeiMaomao
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class ControllerEndpointAspect extends BaseAspectSupport {

    private final ILogService logService;

    private static final Cache<String, Object> CACHES = CacheBuilder.newBuilder()
            // 最大缓存 1000 个
            .maximumSize(10000)
            // 设置写缓存后 3 秒钟过期
            .expireAfterWrite(3, TimeUnit.SECONDS)
            .build();

    @Pointcut("@annotation(com.cls.common.annotation.ControllerEndpoint)")
    public void pointcut() {
    }


    @Before("pointcut()")
    public void before(JoinPoint point) {
        Method targetMethod = resolveMethod(point);
        String methodName = targetMethod.getName();
        int code = Arrays.hashCode(point.getArgs());
        Serializable sessionId = SecurityUtils.getSubject().getSession().getId().hashCode();
        String key = methodName + "-" + code + "-" + sessionId;
        System.err.println(System.currentTimeMillis() + "--------->" + key);
        if (null != CACHES.getIfPresent(key)) {
            throw new RepeatSubmitException("请勿重复提交");
        }
        CACHES.put(key, 1);
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws MyException {
        Object result;
        Method targetMethod = resolveMethod(point);
        ControllerEndpoint annotation = targetMethod.getAnnotation(ControllerEndpoint.class);
        String operation = annotation.operation();
        long start = System.currentTimeMillis();

        try {
            result = point.proceed();
            if (StringUtils.isNotBlank(operation)) {
                RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) attributes;
                String ip = StringUtils.EMPTY;
                if (servletRequestAttributes != null) {
                    ip = servletRequestAttributes.getRequest().getRemoteAddr();
                }
                // 设置操作用户
                User user = (User) SecurityUtils.getSubject().getPrincipal();
                logService.saveLog(user, point, targetMethod, ip, operation, start);
            }
            return result;
        } catch (RepeatSubmitException repeatSubmitException) {
            throw new RepeatSubmitException("请勿重复提交");

        } catch (Throwable throwable) {
            log.error(throwable.getMessage(), throwable);
            String exceptionMessage = annotation.exceptionMessage();
            String message = throwable.getMessage();
            String error = MyUtil.containChinese(message) ? exceptionMessage + "，" + message : exceptionMessage;
            throw new MyException(error);
        }
    }
}



